package com.storyroad.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONException;
import org.json.JSONObject;

import com.storyroad.utils.DBConnection;
import com.storyroad.utils.TableNames;
import com.storyroad.utils.Utilities;

/**
 * Servlet implementation class SignUp
 */
public class SignUp extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private final String defaultProfilePicture = "http://pelotoncafe.com.au/wp-content/plugins/pc_rider_database/images/default_profile_image.png";

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public SignUp() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * Carries out the registration operation for a guest user. In order to successfully register to the system, a unique
	 * username and e-mail address is required. If either of them already exists in the system, the registration attempt
	 * will fail.
	 * @param request HttpServletRequest object that contains data coming from front-end
	 * @param response HttpServletResponse object that contains data which is prepared after processing the incoming data
	 * @throws ServletException
	 * @throws IOException
	 */
	protected void processRequest(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		String f_email = request.getParameter("email");
		String f_password = request.getParameter("password");
		String f_confirmPassword = request.getParameter("confirmPassword");
		String f_username = request.getParameter("username");
		String f_requestType = request.getParameter("request_type");
		String f_photoLink = defaultProfilePicture;
		Connection conn = new DBConnection().connect();
		PrintWriter out = response.getWriter();

		boolean signUpSuccess = false;
		int errorCode = 0;

		response.setContentType("application/json");
		if (conn == null) {
			out.println("Connection error");
		} else {
			try {
				boolean hasError = false;
				// Check whether the two password fields match.
				if (f_password.equals(f_confirmPassword)) {
					// Passwords matched. Now check whether the username provided already exists in the system.
					if (usernameAlreadyExists(conn, f_username)) {
						// Username already exists. Generate an error message. Registration failed.
						request.setAttribute("signup_success", false);
						request.setAttribute("errorCode", "Username");
						signUpSuccess = false;
						errorCode = 1;
						hasError = true;
					}
					// Username is unique. Now check whether the e-mail is unique.
					if (!hasError && emailAlreadyExists(conn, f_email)) {
						// E-mail already exists. Generate an error message. Registration failed.
						request.setAttribute("signup_success", false);
						request.setAttribute("errorCode", "Email");
						signUpSuccess = false;
						errorCode = 2;
						hasError = true;
					}
					// If all provided information is valid then complete registration.
					if (!hasError) {
						String hashedPassword = Utilities.hashPassword(f_password);
						PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + TableNames.USERS_TABLE
										+ "(u_id,email,username,password,photoLink) VALUES(?,?,?,?,?)");
						stmt.setNull(1, Types.INTEGER);
						stmt.setString(2, f_email);
						stmt.setString(3, f_username);
						stmt.setString(4, hashedPassword);
						stmt.setString(5, f_photoLink);
						int result = stmt.executeUpdate();
						if (result == 1) {
							request.setAttribute("signup_success", true);
							signUpSuccess = true;
						} else {
							request.setAttribute("signup_success", false);
							signUpSuccess = false;
						}
					}
				} else {
					// Two passwords field do not match. Generate an error message. Registration failed.
					request.setAttribute("signup_success", false);
					request.setAttribute("errorCode", "Confirm");
					signUpSuccess = false;
					errorCode = 3;
					hasError = true;
				}
				if (f_requestType.equals("Android")) {
					JSONObject signUpResultJsonObject = new JSONObject();
					try {
						signUpResultJsonObject.put("signUpSuccess",	signUpSuccess);
						signUpResultJsonObject.put("errorCode", errorCode);
					} catch (JSONException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					out.print(signUpResultJsonObject.toString());
				} else if (f_requestType.equals("Web")) {
					// After the operation is completed, redirect to the login page.
					request.getRequestDispatcher("LoginPage.jsp").forward(request, response);
				}
			} catch (SQLException e) {
				out.print(e.getMessage());
				e.printStackTrace();
			}
			try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	/**
	 * Checks whether the username provided by the user who is attempting to register already exists in the system.
	 * @param conn connection object to communicate with the database
	 * @param username username provided by the user who is attempting to register to the system
	 * @return @c true if the username provided in the registration form already exists in the system, @c false otherwise
	 */
	protected boolean usernameAlreadyExists(Connection conn, String username) {
		try {
			PreparedStatement usernameCheck = conn.prepareStatement("SELECT * FROM " + TableNames.USERS_TABLE + " WHERE username = ?");
			usernameCheck.setString(1, username);
			ResultSet resultSet1 = usernameCheck.executeQuery();
			if (resultSet1.next()) {
				return true;
			}
			return false;
		} catch (SQLException ex) {
			System.out.println(ex.getMessage());
		}

		return false;
	}

	/**
	 * Checks whether the e-mail provided by the user who is attempting to register already exists in the system.
	 * @param conn connection object to communicate with the database
	 * @param email e-mail provided by the user who is attempting to register to the system
	 * @return @c true if the e-mail provided in the registration form already exists in the system, @c false otherwise
	 */
	protected boolean emailAlreadyExists(Connection conn, String email) {
		try {
			PreparedStatement emailCheck = conn.prepareStatement("SELECT * FROM " + TableNames.USERS_TABLE + " WHERE email = ?");
			emailCheck.setString(1, email);
			ResultSet resultSet2 = emailCheck.executeQuery();
			if (resultSet2.next()) {
				return true;
			}
			return false;
		} catch (SQLException ex) {
			System.out.println(ex.getMessage());
		}

		return false;
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		processRequest(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		processRequest(request, response);
	}

}
